/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import {
  BaseCommand,
  FeatureManager,
  pickedLineData,
  pickedModelData,
} from '@amcax/base';
import {
  BasePickInputRJSFFormat,
  NumberInputFormat,
  PickInputRJSFFormat,
} from '@app-cad/common/components/command-form/constants';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { composeFormat } from '@app-cad/common/components/command-form/utils';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { previewer } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { FeaturedCmdDialogParams } from '@app-cad/types';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useMemo, useState } from 'react';
import { useDollyCamera } from '../../../../product/commands/common/hooks/useDollyCamera';

enum LinearArrayMode {
  LINEAR = 'linear',
  DOUBLELINEAR = 'doubleLinear',
}

type FormData = {
  base: pickedModelData;
  mode: LinearArrayMode;
  distance: number;
  count: number;
  direction: pickedLineData;
  direction2: pickedLineData;
  reverse: boolean;
  reverse2: boolean;
  distance1: number;
  count1: number;
  distance2: number;
  count2: number;
};

function LinearArray({
  title,
  onClose,
  placement,
  props,
}: FeaturedCmdDialogParams) {
  useDollyCamera();

  const initData: FormData = {
    base: null,
    mode: LinearArrayMode.LINEAR,
    distance: 10,
    count: 4,
    direction: null,
    direction2: null,
    reverse: false,
    reverse2: false,
    distance1: 10,
    count1: 4,
    distance2: 10,
    count2: 4,
  };
  const [formData, setFormData] = useState<FormData>(initData);
  const { picker } = useTools();

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const baseID = props.baseid;
    const baseObj =
      baseID && (picker.generatePickObjByPickID(baseID) as pickedModelData);

    const {
      mode,
      direction,
      direction2,
      distance,
      distance1,
      distance2,
      count,
      count1,
      count2,
      reverse,
      reverse2,
    } = props.params;

    const dirObj =
      direction &&
      (picker.generatePickObjByPickID(direction) as pickedLineData);
    const dir2Obj =
      direction2 &&
      (picker.generatePickObjByPickID(direction2) as pickedLineData);

    await initEditDependency([baseID, direction, direction2]);

    setFormData({
      base: baseObj,
      mode: mode,
      direction: dirObj,
      direction2: dir2Obj,
      distance: distance,
      distance1: distance1,
      distance2: distance2,
      count: count,
      count1: count1,
      count2: count2,
      reverse: reverse,
      reverse2: reverse2,
    });
  }, [props?.baseid, props?.shape]);

  useAsyncEffect(async () => {
    if (!isFormDataValid()) {
      previewer.clear();
      return;
    }
    await execute(true);
  }, [formData]);

  const isFormDataValid = () => {
    const {
      base,
      mode,
      direction,
      direction2,
      distance,
      distance1,
      distance2,
      count,
      count1,
      count2,
      reverse,
      reverse2,
    } = formData;

    if (mode === LinearArrayMode.LINEAR) {
      return (
        base != null &&
        direction != null &&
        count != null &&
        distance != null &&
        reverse != null
      );
    } else if (mode === LinearArrayMode.DOUBLELINEAR) {
      return (
        base != null &&
        direction != null &&
        direction2 != null &&
        count1 != null &&
        count2 != null &&
        distance1 != null &&
        distance2 != null &&
        reverse != null &&
        reverse2 != null
      );
    } else {
      return false;
    }
  };

  const finishValid = useMemo(isFormDataValid, [formData]);

  const addDynamicParams = (
    params: Record<string, any>,
    dynamicParams: Record<string, any>,
  ) => {
    return { ...params, ...dynamicParams };
  };

  const execute = async (preview: boolean = false) => {
    const {
      base,
      mode,
      direction,
      direction2,
      distance,
      distance1,
      distance2,
      count,
      count1,
      count2,
      reverse,
      reverse2,
    } = formData;
    const baseID = getIdOfPickedObj(base);
    const params = {
      mode: mode,
      direction: getIdOfPickedObj(direction),
    };
    let dynamicParams = {};
    switch (mode) {
      case LinearArrayMode.LINEAR:
        dynamicParams = {
          count: count,
          distance: distance,
          reverse: reverse,
        };
        break;
      case LinearArrayMode.DOUBLELINEAR:
        dynamicParams = {
          equal: false,
          count1: count1,
          count2: count2,
          distance1: distance1,
          distance2: distance2,
          direction2: getIdOfPickedObj(direction2),
          reverse: reverse,
          reverse2: reverse2,
        };
        break;
    }
    const validParams = addDynamicParams(params, dynamicParams);
    const res =
      props == null
        ? await wsApi.createArray(baseID, validParams, preview)
        : await wsApi.setParams((props as any).dxid, validParams, preview);

    if (preview) {
      await previewInCommand(res);
    }

    return res;
  };

  const checkAndFinish = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute();

    exit();
  };

  const exit = () => {
    previewer.clear();
    onClose();
  };

  // =================
  const { initEditDependency, previewInCommand } = useCommand('array-linear', {
    onClose,
    finishDraw: checkAndFinish,
  });

  const schema = useMemo(() => {
    const modeSchema = {
      type: 'string',
      title: '模式',
      default: LinearArrayMode.LINEAR,
      oneOf: [
        {
          type: 'string',
          title: '单向',
          const: LinearArrayMode.LINEAR,
        },
        {
          type: 'string',
          title: '双向',
          const: LinearArrayMode.DOUBLELINEAR,
        },
      ],
    };

    // 间距 & 单向
    if (formData.mode === LinearArrayMode.LINEAR) {
      return {
        properties: {
          mode: modeSchema,
          base: {
            type: 'string',
            format: FeatureManager.isFeatureEnabled('array-for-hole')
              ? PickInputRJSFFormat.PickVertexOrLineOrFaceOrModelOrArray
              : composeFormat([
                  BasePickInputRJSFFormat.PickVertex,
                  BasePickInputRJSFFormat.PickModel,
                  BasePickInputRJSFFormat.PickPartArray,
                ]),
          },
          direction: {
            type: 'string',
            format: PickInputRJSFFormat.PickDirection,
          },
          count: {
            type: 'number',
            title: '阵列数量',
            default: 4,
            format: NumberInputFormat.Integer,
            minimum: 2,
          },
          distance: {
            type: 'number',
            title: '相邻间距',
            default: 10,
            format: NumberInputFormat.Length,
          },
        },
      };
    }

    // 间距 & 双向
    if (formData.mode === LinearArrayMode.DOUBLELINEAR) {
      return {
        properties: {
          mode: modeSchema,
          base: {
            type: 'string',
            format: FeatureManager.isFeatureEnabled('array-for-hole')
              ? PickInputRJSFFormat.PickVertexOrLineOrFaceOrModelOrArray
              : composeFormat([
                  BasePickInputRJSFFormat.PickVertex,
                  BasePickInputRJSFFormat.PickModel,
                  BasePickInputRJSFFormat.PickPartArray,
                ]),
          },
          direction: {
            type: 'string',
            format: PickInputRJSFFormat.PickDirection,
          },
          count1: {
            type: 'number',
            title: '阵列数量1',
            default: 4,
            format: NumberInputFormat.Integer,
          },
          distance1: {
            type: 'number',
            title: '间距1',
            default: 10,
            format: NumberInputFormat.Length,
          },
          direction2: {
            type: 'string',
            format: PickInputRJSFFormat.PickDirection,
          },
          count2: {
            type: 'number',
            title: '阵列数量2',
            default: 4,
            format: NumberInputFormat.Integer,
          },
          distance2: {
            type: 'number',
            title: '间距2',
            default: 10,
            format: NumberInputFormat.Length,
          },
        },
      };
    }

    return schema;
  }, [formData.mode]);

  return (
    <PickableCommandForm
      isFormDataValid={finishValid}
      disabled={false}
      onClose={exit}
      title={title}
      placement={placement}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        setFormData(v);
      }}
      extraUiSchema={{
        mode: {
          'ui:widget': 'radio',
          'ui:classNames': 'command-form__mode-switch',
        },
        base: {
          'ui:placeholder': '请输入目标模型',
          'ui:autofocus': true,
        },
        direction: {
          'ui:placeholder': '请输入阵列方向1',
        },
        direction2: {
          'ui:placeholder': '请输入阵列方向2',
        },
        distance: {
          'ui:options': {
            showReverse: true,
            onReverseChange: (isReverse) => {
              setFormData((prevFormData) => ({
                ...prevFormData,
                reverse: isReverse,
              }));
            },
          },
        },
        distance1: {
          'ui:options': {
            showReverse: true,
            onReverseChange: (isReverse) => {
              setFormData((prevFormData) => ({
                ...prevFormData,
                reverse: isReverse,
              }));
            },
          },
        },
        distance2: {
          'ui:options': {
            showReverse: true,
            onReverseChange: (isReverse) => {
              setFormData((prevFormData) => ({
                ...prevFormData,
                reverse2: isReverse,
              }));
            },
          },
        },
      }}
      submitText='完成'
      onSubmit={checkAndFinish}
    ></PickableCommandForm>
  );
}

export const cmdLinearArray: BaseCommand = {
  id: 'cmdLinearArray',
  label: 'command.linear-array',
  icon: 'commands/feature/array-linear',
  create: (label, onClose, props) => (
    <LinearArray
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
